/** @preserve @@@pack=no 
 * 
 * fhs_menu 0.1
 *
 * based on:
 * jQuery UI Menu 1.9m7
 *
 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu
 *
 * Depends:
 *    jquery.ui.core.js
 *    jquery.ui.widget.js
 */ 
(function ($) {
  var idIncrement = 0;
  $.widget("ui.fhs_menu", {
    version: "0.1",
    defaultElement: "<ul>",
    delay: 300,
    options: {
      menus: "ul",
      position: {
        my: "left top",
        at: "right top"
      },
      // callbacks
      blur: null,
      focus: null,
      select: null
    },
    _create: function () {
      this.activeMenu = this.element;
      this.menuId = this.element.attr("id") || "ui-menu-" + idIncrement++;
      if (this.element.find(".ui-icon").length) {
        this.element.addClass("ui-menu-icons");
      }
      var items = this.items = this.element.children("li");
      items.each(function () {
        if ($(this).hasClass("fhs_menu-select")) {
          $(this).children("a").wrapInner("<span class='ui-button-text'></span>");
          $(this).children("a").addClass("ui-menu-icons").children(":first").before("<span class=\"ui-button-icon-primary ui-icon ui-icon-check\"></span>");
        }
      });
      this.element.find("a").addClass("ui-button-text");
      this.element.addClass("ui-menu ui-widget-header").attr({
        id: this.menuId,
        role: "menu"
      })
      // need to catch all clicks on disabled menu
      // not possible through _bind
      .bind("click.fhs_menu", $.proxy(function (event) {
        if (this.options.disabled) {
          event.preventDefault();
        }
      }, this));
      if (this.options.disabled) {
        this.element.addClass("ui-state-disabled");
      }
      this._bind({
        // Prevent focus from sticking to links inside menu after clicking
        // them (focus should always stay on UL during navigation).
        "mousedown .ui-menu-item > a": function (event) {
          event.preventDefault();
        },
        "click .ui-state-disabled > a": function (event) {
          event.preventDefault();
        },
        "click .ui-menu-item:has(a)": function (event) {
          event.stopImmediatePropagation();
          //Don't select disabled menu items
          if (!$(event.target).closest(".ui-menu-item").is(".ui-state-disabled")) {
            this.select(event);
            // Redirect focus to the menu with a delay for firefox
            this._delay(function () {
              if (!this.element.is(":focus")) {
                this.element.focus();
              }
            }, 20);
          }
        },
        "mouseover .ui-menu-item": function (event) {
          event.stopImmediatePropagation();
          var target = $(event.currentTarget);
          // Remove ui-state-active class from siblings of the newly focused menu item to avoid a jump caused by adjacent elements both having a class with a border
          target.siblings().children(".ui-state-active").removeClass("ui-state-active");
          this.focus(event, target);
        },
        "mouseleave": "collapseAll",
        "mouseleave .ui-menu": "collapseAll",
        "focus": function (event) {
          var firstItem = this.element.children(".ui-menu-item").not(".ui-state-disabled").eq(0);
          if (this.active) {
            firstItem = this.active;
          }
          this.focus(event, firstItem);
        },
        blur: function (event) {
          this._delay(function () {
            if (this.document == undefined) return;
            if (!$.contains(this.element[0], this.document[0].activeElement)) {
              this.collapseAll(event);
            }
          }, 0);
        }
      });
      this.refresh();
      this.element.attr("tabIndex", 0);
      this._bind(this.document, {
        click: function (event) {
          if (!$(event.target).closest(".ui-menu").length) {
            this.collapseAll(event);
          }
        }
      });
    },
    _destroy: function () {
      //destroy (sub)menus
      this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget-header ui-corner-all").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").show();
      //destroy menu items
      this.element.find(".ui-menu-item").unbind(".menu").removeClass("ui-menu-item").removeAttr("role").children("a").removeClass("ui-corner-all").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").removeAttr("id").children(".ui-icon").remove();
    },
    refresh: function () {
      // initialize nested menus
      var submenus = this.element.find(this.options.menus + ":not( .ui-menu )").addClass("ui-menu ui-widget-header ui-corner-all").attr("role", "menu").hide().attr("aria-hidden", "true").attr("aria-expanded", "false");
      // don't refresh list items that are already adapted
      var menuId = this.menuId;
      submenus.add(this.element).children(":not( .ui-menu-item ):has( a )").addClass("ui-menu-item").attr("role", "presentation").children("a").addClass("ui-corner-all").attr("tabIndex", -1).attr("role", "menuitem").attr("id", function (i) {
        return menuId + "-" + i;
      });
      submenus.each(function () {
        var menu = $(this),
          item = menu.prev("a");
        item.attr("aria-haspopup", "true").prepend('<span class="ui-menu-icon ui-icon ui-icon-carat-1-e"></span>');
        menu.attr("aria-labelledby", item.attr("id"));
      });
    },
    focus: function (event, item) {
      this.blur(event);
      this.active = item.first().children("a").addClass("ui-state-focus").end();
      this.element.attr("aria-activedescendant", this.active.children("a").attr("id"));
      // highlight active parent menu item, if any
      this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active");
      this.timer = this._delay(function () {
        this._close();
      }, this.delay);
      var nested = $("> .ui-menu", item);
      if (nested.length && (/^mouse/.test(event.type))) {
        this._startOpening(nested);
      }
      this.activeMenu = item.parent();
      this._trigger("focus", event, {
        item: item
      });
    },
    blur: function (event) {
      clearTimeout(this.timer);
      if (!this.active) {
        return;
      }
      this.active.children("a").removeClass("ui-state-focus");
      this.active = null;
      this._trigger("blur", event, {
        item: this.active
      });
    },
    _startOpening: function (submenu) {
      clearTimeout(this.timer);
      // Don't open if already open fixes a Firefox bug that caused a .5 pixel
      // shift in the submenu position when mousing over the carat icon
      if (submenu.attr("aria-hidden") !== "true") {
        return;
      }
      this.timer = this._delay(function () {
        this._close();
        this._open(submenu);
      }, this.delay);
    },
    _open: function (submenu) {
      clearTimeout(this.timer);
      this.element.find(".ui-menu").not(submenu.parents()).hide().attr("aria-hidden", "true");
      var position = $.extend({}, {
        of: this.active
      }, $.type(this.options.position) == "function" ? this.options.position(this.active) : this.options.position);
      submenu.show().removeAttr("aria-hidden").attr("aria-expanded", "true").position(position);
    },
    collapseAll: function (event, all) {
      clearTimeout(this.timer);
      this.timer = this._delay(function () {
        // if we were passed an event, look for the submenu that contains the event
        var currentMenu = all ? this.element : $(event && event.target).closest(this.element.find(".ui-menu"));
        // if we found no valid submenu ancestor, use the main menu to close all sub menus anyway
        if (!currentMenu.length) {
          currentMenu = this.element;
        }
        this._close(currentMenu);
        this.blur(event);
        this.activeMenu = currentMenu;
      }, this.delay);
    },
    // With no arguments, closes the currently active menu - if nothing is active
    // it closes all menus.  If passed an argument, it will search for menus BELOW
    _close: function (startMenu) {
      if (!startMenu) {
        startMenu = this.active ? this.active.parent() : this.element;
      }
      startMenu.find(".ui-menu").hide().attr("aria-hidden", "true").attr("aria-expanded", "false").end().find("a.ui-state-active").removeClass("ui-state-active");
    },
    collapse: function (event) {
      var newItem = this.active && this.active.parent().closest(".ui-menu-item", this.element);
      if (newItem && newItem.length) {
        this._close();
        this.focus(event, newItem);
        return true;
      }
    },
    expand: function (event) {
      var newItem = this.active && this.active.children(".ui-menu ").children(".ui-menu-item").not(".ui-state-disabled").first();
      if (newItem && newItem.length) {
        this._open(newItem.parent());
        //timeout so Firefox will not hide activedescendant change in expanding submenu from AT
        this._delay(function () {
          this.focus(event, newItem);
        }, 20);
        return true;
      }
    },
    select: function (event) {
      // save active reference before collapseAll triggers blur
      var ui = {
        item: this.active
      };
      this.collapseAll(event, true);
      this._trigger("select", event, ui);
    }
  });
}(jQuery));